package nil.ed.simulator.request.scheduler.impl;

import com.google.common.collect.Sets;
import lombok.Getter;
import nil.ed.simulator.request.enums.events.EventMode;
import nil.ed.simulator.request.enums.events.EventType;
import nil.ed.simulator.request.event.Event;
import nil.ed.simulator.request.event.bus.EventBus;
import nil.ed.simulator.request.guice.GuiceManager;
import nil.ed.simulator.request.scheduler.ScheduleUnit;

import java.util.Set;
import java.util.concurrent.*;

/**
 * @author lidelin.
 */
public class CycleThreadPoolExecutor extends ThreadPoolExecutor {

    @Getter
    private final Set<Runnable> schedulingTasks = Sets.newConcurrentHashSet();

    public CycleThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public CycleThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public CycleThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public CycleThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        schedulingTasks.add(r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        if (r instanceof ScheduleUnit) {
            if (!((ScheduleUnit) r).isTerminate()) {
                getQueue().offer(r);
            }
        }
        schedulingTasks.remove(r);
        GuiceManager.INJECTOR.getInstance(EventBus.class).publish(Event.builder()
                .source(null)
                .eventType(EventType.SCHEDULER_FINISH)
                .eventMode(EventMode.ASYNC)
                .data(r)
                .build());
    }
}
